﻿using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace CWM.Skinn
{
    public static partial class SkinnContextCommands
    {
        public static partial class ToolTips
        {
            public const string RendererBoneExplode = "Split a mesh into separate meshes by bone-weights" +
               "Works on a mesh with one sub-mesh. " +
               "The source is disabled and new renderers are created.";
        }

        [CtxMenuItem("Renderer/SubMesh/Split/Bones/All", ToolTips.RendererBoneExplode,
       ContextRequirements.SingleSubMesh, 0)]
        public static void RendererBoneExplodeAll()
        {
            var item = SkinnContext.GetContextItem();
            var context = item.GetComponent<SkinnedMeshRenderer>();
            if (SkinnEx.IsNullOrNotInAScene(context)) { SkinnContext.Finished(); return; }
            if (!SkinnEx.HasMinimumRequirements(context)) { SkinnContext.Finished(); return; }
            if (!SkinnContext.IsVertexCountOkay(context, "generation may take awhile.", 5500)) { SkinnContext.Finished(); return; }

            RendererBonesExplode(context, null);
            SkinnContext.Finished();
        }


        [CtxMenuItem("Renderer/SubMesh/Split/Bones/Hierarchical", ToolTips.RendererBoneExplode,
      ContextFlag.Bone, ContextRequirements.SingleSubMesh, 0)]
        public static void RendererBoneExplode()
        {
            var item = SkinnContext.GetContextItem();
            var context = item.GetComponent<SkinnedMeshRenderer>();
            if (SkinnEx.IsNullOrNotInAScene(context)) { SkinnContext.Finished(); return; }
            if (!SkinnEx.HasMinimumRequirements(context)) { SkinnContext.Finished(); return; }
            if (!SkinnContext.IsVertexCountOkay(context, "generation may take awhile.", 6500)) { SkinnContext.Finished(); return; }

            GameObject boneContext0 = SkinnEx.FindGameObject(SkinnContext.ContextBone0);

            var childern = boneContext0.transform.GetAllChildren(true);
            var bones = context.bones;
            var bonesSelection = new bool[bones.Length];

            for (int i = 0; i < bones.Length; i++)
            {
                var bone = bones[i]; if (!bone) continue;
                bonesSelection[i] = childern.Find((a) => { return a.GetInstanceID() == bone.GetInstanceID(); });
            }

            RendererBonesExplode(context, bonesSelection, boneContext0.name);
            SkinnContext.Finished();
        }

        private static void RendererBonesExplode(SkinnedMeshRenderer context, bool [] bones = null, string boneName = "")
        {
            List<Object> selected = new List<Object>();

            Mesh[] meshes;
            if (!SkinnEx.GetMeshBoneIslands(context, out meshes, bones)) return;

            var root = new GameObject(context.name);
            root.transform.SetParent(context.transform.parent);
            Undo.RegisterCreatedObjectUndo(root, "Split Bones");

            for (int i = 0; i < meshes.Length; i++)
            {
                if (!meshes[i]) continue;
                var renderer = context.Clone(true) as SkinnedMeshRenderer;
                renderer.SetSharedMesh(meshes[i]);
                renderer.transform.SetParent(root.transform);

                if (SkinnEx.IsNullOrEmpty(bones))
                    renderer.name += string.Format("_{0}_{1}", SkinnEx.EnforceString(meshes[i].name), i);
                else if (i == 0) renderer.name += boneName;

                SkinnContext.OptimizeMesh(renderer);

                Undo.RegisterCreatedObjectUndo(renderer.gameObject, "Split Bones");
                selected.Add(renderer.gameObject);
            }


            SkinnContext.UndoRecord(context, "Split Bones");
            context.gameObject.SetActive(false);

            if (selected.Count > 0) Selection.objects = selected.ToArray();
        }

    }
}